﻿using Leeder.Enum;
using Leeder.Logger;
using Leeder.Model;
using Leeder.Plugin;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TriaServer.Business;
using TriaServer.Enum;
using TriaServer.Model;
using static Common.Logging.Configuration.ArgUtils;

namespace TriaServer
{
    public class TriaService
    {
        private LogOperate LogObj => Log.GetLogger(this.GetType());
        ReceivesMessageBLL receivesMessageBLL = new ReceivesMessageBLL();
        QueueInfoBLL queueInfoBLL = new QueueInfoBLL();
        ProductionModelsBLL productionModelsBLL = new ProductionModelsBLL();
        TriaConfigBLL triaConfigBLL = new TriaConfigBLL();

        /// <summary>
        /// Tria对象(接收生产指示)
        /// </summary>
        private TriaHandler triaHandler;
        /// <summary>
        /// Tria(端末)配置
        /// </summary>
        public TriaConfigModel TriaConfig;
        /// <summary>
        /// Tria下发生产指示缓存队列，缓存队列处理，防止一次性下发数据较多处理出异常，先缓存再通过其他线程一条条解析处理
        /// </summary>
        private ConcurrentQueue<string> TriaQueue;
        /// <summary>
        /// 消息通知事件
        /// </summary>
        public event Action<string, MessageType> MesgNotificationEvent;
        /// <summary>
        /// 端末状态事件
        /// </summary>
        public event Action<bool> TriaStateEvent;

        /// <summary>
        /// 单例模式
        /// </summary>
        private static TriaService instance = new TriaService();
        public static TriaService getInstance()
        {
            if (instance == null)
                instance = new TriaService();
            return instance;
        }

        private TriaService()
        {

        }

        public bool Init()
        {
            MesgNotificationEvent?.BeginInvoke($"系统初始化...", MessageType.Info, null, null);
            TriaConfig = triaConfigBLL.GetConfig();
            if (TriaConfig != null)
            {
                MesgNotificationEvent?.BeginInvoke($"端末配置加载成功！", MessageType.Info, null, null);
            }
            else
            {
                MesgNotificationEvent?.BeginInvoke($"端末配置加载失败！", MessageType.Error, null, null);
                return false;
            }
            TriaQueue = new ConcurrentQueue<string>();
            var result = InitTria(out triaHandler, TriaConfig.Logic_Length, TriaConfig.Tria_Ip, TriaConfig.Tria_Port);
            if(result)
            {
                lockObj = new object();
                TriaDataQueueResolve();
                MesgNotificationEvent?.BeginInvoke($"系统初始化完成！", MessageType.Info, null, null);
            }
            else
            {
                MesgNotificationEvent?.BeginInvoke($"系统初始化失败！", MessageType.Error, null, null);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 初始化端末
        /// </summary>
        public bool InitTria(out TriaHandler handler, int logicLength, string triaIp, int triaPort)
        {
            try
            {
                MesgNotificationEvent?.BeginInvoke($"初始化端末({triaIp}:{triaPort})...", MessageType.Info, null, null);
                LogObj.Info("初始化端末...");
                LogObj.Info($"连接{triaIp}:{triaPort}...");
                handler = new TriaHandler(triaIp, triaPort);
                handler.SetLogicLength(logicLength);
                handler.OnResolve += OnTriaDataResolve;
                handler.Start();
                DeviceStateChange("Tria", true);
                LogObj.Info("端末初始化成功!");
                MesgNotificationEvent?.BeginInvoke($"端末初始化成功!", MessageType.Info, null, null);
                TriaStateEvent?.BeginInvoke(true,null,null);
                return true;
            }
            catch (Exception ex)
            {
                LogObj.Error("端末初始化失败：" + ex.ToString());
                MesgNotificationEvent?.BeginInvoke($"端末初始化失败!{ex.Message}", MessageType.Error, null, null);
                handler = default;
                ReInitTria(logicLength, triaIp, triaPort);
                TriaStateEvent?.BeginInvoke(false, null, null);
                return false;
            }
        }

        /// <summary>
        /// Tria数据处理队列
        /// </summary>
        public void ReInitTria(int logicLength, string triaIp, int triaPort)
        {
            Thread thread = new Thread(() =>
            {
                LogObj.Info("Tria初始化线程");
                while (true)
                {
                    try
                    {
                        MesgNotificationEvent?.BeginInvoke($"重新初始化端末...", MessageType.Info, null, null);
                        LogObj.Info($"重新初始化端末（{triaIp}:{triaPort}）...");
                        triaHandler = new TriaHandler(triaIp, triaPort);
                        triaHandler.SetLogicLength(logicLength);
                        triaHandler.OnResolve += OnTriaDataResolve;
                        triaHandler.Start();
                        DeviceStateChange("Tria", true);
                        LogObj.Info("端末初始化成功!");
                        TriaStateEvent?.BeginInvoke(true, null, null);
                        return;
                    }
                    catch (Exception ex)
                    {
                        LogObj.Error($"端末（{triaIp}:{triaPort}）初始化失败：{ex.ToString()}");
                        triaHandler = default;
                    }
                    Thread.Sleep(30000);
                }
            }
            );
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// Tria数据处理队列
        /// </summary>
        public void TriaDataQueueResolve()
        {
            Thread thread = new Thread(() =>
            {
                LogObj.Info("Tria数据处理线程启动!");
                while (true)
                {
                    if (!TriaQueue.IsEmpty)
                    {
                        string data;
                        TriaQueue.TryDequeue(out data);
                        if (data != null)
                        {
                            LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "  端末接收数据：" + data);
                            MesgNotificationEvent?.BeginInvoke($"端末接收数据：{data}", MessageType.Info, null, null);
                            // 先解析VinNo,然后通过VinNo去队列表找该数据是否存在
                            try
                            {
                                QueueInfoModel queueInfo = ParseQueueInfo(data);
                                // 插入一条数据到报文历史记录表
                                SaveReceivesMessage(data, queueInfo);
                            }
                            catch (Exception ex1)
                            {
                                LogObj.Error(ExceptionType.BusinessException, ex1, "处理接收数据异常!");
                            }
                        }
                        Thread.Sleep(100);
                    }
                    else
                    {
                        Thread.Sleep(1000);
                    }
                }
            }
            );
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// 接收Tria数据的事件
        /// </summary>
        /// <param name="data">Tria数据</param>
        /// <param name="model">Tria对象</param>
        /// <param name="result">Tria数据的处理结果</param>
        public void OnTriaDataResolve(string data, TriaModel model, TriaProcessResult result)
        {
            try
            {
                TriaQueue.Enqueue(data);
            }
            catch (Exception ex)
            {
                MesgNotificationEvent?.BeginInvoke($"接收数据异常：{ex.Message}", MessageType.Error, null, null);
                LogObj.Error(ExceptionType.BusinessException, ex, "接收数据异常!");
            }
        }

        /// <summary>
        /// 保存报文历史数据
        /// </summary>
        /// <param name="data">Tria数据</param>
        /// <param name="queueInfo"></param>
        public void SaveReceivesMessage(string data, QueueInfoModel queueInfo)
        {
            try
            {
                if (null == queueInfo)
                {
                    receivesMessageBLL.Add(new ReceivesMessageModel { Created_Date = DateTime.Now, Receive_Content = data, Point = "Error" });
                    return;
                }
                string point = data.Substring(TriaConfig.Point_Position, TriaConfig.Point_Length);
                //if (point != "H1" && point != "H0" && point != "N0") point = "Error";
                receivesMessageBLL.Add(new ReceivesMessageModel
                {
                    Created_Date = DateTime.Now,
                    Receive_Content = data,
                    Sequence = queueInfo.Sequence,
                    Body_Num = queueInfo.Body_Num,
                    VIN = queueInfo.VIN,
                    Point = point,
                    Little_Time = DateTime.Now
                });
                if (queueInfo.ID == 0)
                {
                    queueInfoBLL.Add(queueInfo);
                }
                else
                {
                    queueInfoBLL.Update(queueInfo);
                    MesgNotificationEvent?.BeginInvoke($"数据重复发送：{queueInfo.VIN}", MessageType.Info, null, null);
                    LogObj.Error($"队列重复发送![{queueInfo.VIN}]");
                }
            }
            catch (Exception ex)
            {
                MesgNotificationEvent?.BeginInvoke($"保存数据出错：{ex.Message}", MessageType.Error, null, null);
                LogObj.Error(ExceptionType.BusinessException, ex, $"保存数据出错![{data}]");
            }
        }

        private object lockObj;
        /// <summary>
        /// 解析队列表数据
        /// </summary>
        /// <param name="data">Tria数据</param>
        /// <returns></returns>
        public QueueInfoModel ParseQueueInfo(string data)
        {
            try
            {
                string vinNo = data.Substring(TriaConfig.Vin_No_Position, TriaConfig.Vin_No_Length);
                string point = data.Substring(TriaConfig.Point_Position, TriaConfig.Point_Length);
                QueueInfoModel model;
                // 防止下发速度过快
                lock (lockObj)
                {
                    model = queueInfoBLL.GetQueueInfoModelByVin(vinNo);
                }
                if (model == null)
                {
                    var sequence = int.Parse(data.Substring(TriaConfig.Sequence_Position, TriaConfig.Sequence_Length));
                    var bodyNum = data.Substring(TriaConfig.Car_Body_No_Position, TriaConfig.Car_Body_No_Length);
                    var carCode = data.Substring(TriaConfig.Car_Model_Code_Position, TriaConfig.Car_Model_Code_Length);

                    var partsCode1 = data.Substring(TriaConfig.Parts_Code1_Position, TriaConfig.Parts_Code1_Length);
                    var partsCode2 = data.Substring(TriaConfig.Parts_Code2_Position, TriaConfig.Parts_Code2_Length);

                    model = new QueueInfoModel
                    {
                        VIN = vinNo,
                        Sequence = sequence,
                        Body_Num = bodyNum
                    };
                    model.Car_Code = carCode;
                    model.Parts_Code1 = partsCode1;
                    model.Parts_Code2 = partsCode2;
                }
                model.Status = 0;
                model.Created_Date = DateTime.Now;
                model.Update_Date = DateTime.Now;
                var code = vinNo.Substring(7, 1);
                var productionModel = productionModelsBLL.GetProductionModelsByCondition(code);
                if (productionModel != null)
                    model.Car_Model = productionModel.Model_Name;
                else
                    model.Car_Model = code;
                return model;
            }
            catch (Exception ex)
            {
                MesgNotificationEvent?.BeginInvoke($"解析数据出错：{ex.Message}", MessageType.Error, null, null);
                LogObj.Error(ExceptionType.BusinessException, ex);
                return null;
            }
        }

        /// <summary>
        /// 设备状态变化
        /// </summary>
        /// <param name="deviceName">设备名称</param>
        /// <param name="state">设备状态</param>
        private void DeviceStateChange(string deviceName, bool state)
        {
            //GolbalVariable.DeviceList.Where(s => s.DeviceName == deviceName).FirstOrDefault().DeviceState = state;
            //DeviceStateChangeEvent?.BeginInvoke(deviceName, true, null, null);
        }

        public bool SaveConfig(TriaConfigModel config)
        {
            if (config.ID > 0)
            {
                var result = triaConfigBLL.Update(config);
                if (result.IsSuccess)
                {
                    return true;
                }
                else
                {
                    LogObj.Error($"配置更新失败！{result.Dsca}");
                    return false;
                }
            }
            else
            {
                var result = triaConfigBLL.Add(config);
                if (result.IsSuccess)
                {
                    return true;
                }
                else
                {
                    LogObj.Error($"配置保存失败！{result.Dsca}");
                    return false;
                }
            }
        }
    }
}
